퍼사드 패턴
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
퍼사드 패턴은 복잡한 서브 시스템에 대한 단순화된 인터페이스를 제공하는 디자인 패턴이다. 클라이언트는 퍼사드 클래스를 통해 서브 시스템의 기능에 접근하며, 퍼사드는 서브 시스템 내부의 작업을 위임한다. 이 패턴은 시스템의 복잡성을 줄이고, 클라이언트 코드의 가독성과 유지보수성을 향상시킨다. 퍼사드 패턴은 복잡한 시스템에 접근하기 위한 간단한 인터페이스가 필요하거나, 시스템이 복잡하거나 이해하기 어려울 때, 계층화된 소프트웨어의 각 레벨에 진입점이 필요할 때 사용된다. 추상 팩토리 패턴은 퍼사드 패턴의 구체적인 예시로 볼 수 있으며, 대한민국 전자정부 시스템과 같은 실제 사례에도 적용된다.
더 읽어볼만한 페이지
- 소프트웨어 디자인 패턴 - 모델-뷰-컨트롤러
모델-뷰-컨트롤러(MVC)는 소프트웨어 디자인 패턴으로, 응용 프로그램을 모델, 뷰, 컨트롤러 세 가지 요소로 분리하여 개발하며, 사용자 인터페이스 개발에서 데이터, 표현 방식, 사용자 입력 처리를 분리해 유지보수성과 확장성을 높이는 데 기여한다. - 소프트웨어 디자인 패턴 - 스케줄링 (컴퓨팅)
스케줄링은 운영 체제가 시스템의 목적과 환경에 맞춰 작업을 관리하는 기법으로, 장기, 중기, 단기 스케줄러를 통해 프로세스를 선택하며, CPU 사용률, 처리량 등을 기준으로 평가하고, FCFS, SJF, RR 등의 알고리즘을 사용한다.
| 퍼사드 패턴 | |
|---|---|
| 디자인 패턴 | |
| 유형 | 구조적 패턴 |
| 목적 | 복잡한 서브시스템에 대한 단순화된 인터페이스 제공 |
| 다른 이름 | Wrapper 구조체 (Structure) |
| 개요 | |
| 문제 | 복잡한 시스템은 사용, 이해, 유지보수가 어렵다. 많은 클래스가 서로 의존적이기 때문에 개발자와 사용자는 시스템의 다양한 부분을 추적해야 한다. |
| 해결책 | 퍼사드 패턴은 복잡한 서브시스템에 대한 단순화된 인터페이스를 제공하여 결합도를 줄이고 클라이언트가 더 쉽게 사용할 수 있도록 한다. |
| 구조 | 퍼사드는 일련의 인터페이스를 제공하여 복잡한 서브시스템의 기능을 캡슐화한다. |
| 참여자 | 퍼사드 (Facade): 서브시스템의 복잡성을 숨기고 클라이언트에게 단순화된 인터페이스를 제공한다. 서브시스템 클래스 (Subsystem classes): 퍼사드에 의해 사용되는 클래스들로, 서브시스템의 기능을 구현한다. |
| 협업 | 클라이언트는 퍼사드 객체를 통해 서브시스템과 상호 작용한다. 퍼사드는 서브시스템 객체에 대한 접근을 관리하고 클라이언트의 요청을 적절한 서브시스템 객체에 전달한다. |
| 구현 | |
![]() | |
| C++ 예시 | C++ 예시 |
| C# 예시 | C# 예시 |
| Java 예시 | Java 예시 |
| PHP 예시 | PHP 예시 |
| Python 예시 | Python 예시 |
| TypeScript 예시 | TypeScript 예시 |
| 사용 사례 | |
| 컴파일러 | 컴파일러의 퍼사드는 컴파일러의 전체 단계를 단순화된 인터페이스 뒤에 숨긴다. |
| 전자 상거래 | 온라인 쇼핑 웹 사이트의 주문 처리 시스템. |
| 관련 패턴 | |
| 추상 팩토리 패턴, 빌더 패턴, 프로토타입 패턴 | 퍼사드 패턴은 추상 팩토리 패턴, 빌더 패턴, 프로토타입 패턴과 함께 사용하여 서브시스템을 생성할 수 있다. |
| 중재자 패턴 | 퍼사드 패턴은 중재자 패턴과 유사하지만, 퍼사드 패턴은 서브시스템에 대한 단순화된 인터페이스를 제공하는 반면, 중재자 패턴은 객체 간의 상호 작용을 중앙 집중화한다. |
| 싱글톤 패턴 | 퍼사드 패턴은 싱글톤 패턴을 사용하여 퍼사드 객체의 인스턴스를 하나만 만들 수 있다. |
2. 구조
퍼사드 패턴은 클라이언트가 복잡한 서브시스템의 내부에 직접 접근하는 대신, 퍼사드(Facade)라는 단일 클래스를 통해 서브시스템과 상호작용하는 구조를 가진다.[2] 이는 서브시스템의 사용을 단순화하고, 클라이언트와 서브시스템 간의 결합도를 낮추기 위한 것이다.
아래의 UML 클래스 다이어그램은 퍼사드 패턴의 기본적인 구조를 보여준다.
다이어그램에서 볼 수 있듯이, `Client` 객체는 서브시스템 내부의 여러 클래스들(`SubSystem Class`)을 직접 알 필요 없이, 오직 `Facade` 객체와 통신한다. `Facade`는 서브시스템의 복잡한 인터페이스들을 감싸고, `Client`에게 필요한 기능만을 단순화된 형태로 제공하는 창구 역할을 한다.[4] 즉, `Client`는 `Facade`에만 의존하게 되어 서브시스템의 내부 구현 변경에 영향을 덜 받게 된다.
실행 시에는 `Client`가 `Facade`에 요청을 보내면, `Facade`는 이 요청을 받아 서브시스템 내의 적절한 객체들에게 작업을 위임하여 처리한다.
2. 1. 구성 요소
퍼사드 패턴은 다음과 같은 주요 구성 요소로 이루어진다.; 퍼사드 (Facade)
: 서브시스템(패키지) 1, 2, 3 및 그 밖의 응용 프로그램 코드와 상호 동작하는 클래스이다.
; 클라이언트 (Client)
: 서브시스템(패키지) 내의 리소스들을 접근하기 위해 퍼사드 클래스를 사용하는 객체들이다.
; 패키지 (Package) / 서브시스템 (Subsystem)
: 소프트웨어 라이브러리 / API 집합이다. 퍼사드 클래스를 통해 접근된다.
2. 1. 1. 퍼사드 (Facade)
퍼사드 클래스는 패키지 1, 2, 3 및 그림에 나오지 않은 그 밖의 응용 프로그램 코드와 상호 동작한다. 클라이언트는 패키지 내의 리소스들을 접근하기 위해 퍼사드 클래스를 쓰는 객체들이며, 패키지는 소프트웨어 라이브러리 또는 API 집합으로 퍼사드 클래스를 통해 접근된다.[1]퍼사드 패턴은 유연하고 재사용 가능한 객체 지향 소프트웨어를 설계하기 위한 반복적인 설계 문제를 해결하는 방법을 설명하는 23가지 잘 알려진 ''GoF 디자인 패턴'' 중 하나이다. 즉, 구현, 변경, 테스트 및 재사용이 더 쉬운 객체를 만드는 데 도움을 준다.
퍼사드 디자인 패턴은 다음과 같은 문제를 해결하는 데 사용될 수 있다.[2]
- 복잡한 하위 시스템(subsystem)을 사용하기 쉽게 만들기 위해, 하위 시스템의 인터페이스 집합에 대한 간단한 인터페이스를 제공해야 할 때.
- 하위 시스템에 대한 의존성을 최소화해야 할 때.
복잡한 하위 시스템에 직접 접근하는 클라이언트는 다양한 인터페이스를 가진 여러 다른 객체를 참조하게 되어 긴밀한 결합 상태가 된다. 이는 클라이언트를 구현, 변경, 테스트 및 재사용하기 어렵게 만든다.
퍼사드 디자인 패턴은 이러한 문제에 대해 '퍼사드(Facade)' 객체를 정의하는 해결책을 제시한다. 이 퍼사드 객체는 다음과 같은 역할을 수행한다.
- 하위 시스템의 인터페이스를 기준으로 (작업을 위임하여) 간단한 인터페이스를 구현한다.
- 요청을 하위 시스템에 전달하기 전후에 추가적인 기능을 수행할 수 있다.
이를 통해 클라이언트는 퍼사드 객체를 통해 작업함으로써 하위 시스템에 대한 의존성을 최소화할 수 있다. 아래는 퍼사드 디자인 패턴에 대한 샘플 UML 클래스 다이어그램과 시퀀스 다이어그램이다.
이 UML 클래스 다이어그램에서 `Client` 클래스는 서브시스템 클래스(
Class1, Class2, Class3)에 직접 접근하지 않는다. 대신, `Client`는 서브시스템 클래스를 기준으로 단순한 인터페이스를 구현하는(작업을 위임하는) `Facade` 클래스를 통해 작동한다. `Client`는 단순한 `Facade` 인터페이스에만 의존하며 복잡한 서브시스템과는 독립적이다.[4]시퀀스 다이어그램은 런타임 상호 작용을 보여준다. `Client` 객체는 `Facade` 객체를 통해 작동하며, `Facade` 객체는 요청을 받아 해당 작업을 수행하는 `Class1`, `Class2`, `Class3` 인스턴스에 요청을 위임한다.

퍼사드 클래스는 애플리케이션의 나머지 부분에서 패키지 1, 2, 3을 추상화한다. 객체(클라이언트)는 퍼사드 패턴을 사용하여 패키지의 리소스에 접근한다.
퍼사드 패턴의 예시로, 서브 시스템으로서의 컴파일러를 생각해 볼 수 있다. 컴파일러 시스템은 어휘 분석기나 구문 분석기 등으로 구성되어 있다. 이러한 구성 요소는 새로운 컴파일러나 다른 소프트웨어를 작성하는 데 서브 시스템으로 이용될 수 있다. 그러나 일반 사용자에게 컴파일러는 소스 코드로부터 프로그램을 생성하기 위한 것이며, 소스 코드를 컴파일할 수 있는 기능만 있으면 충분하다. 따라서 서브 시스템으로부터 일반 사용자를 위해 필요한 컴파일 기능만을 호출하는 클래스를 제공하는데, 이 클래스가 바로 퍼사드 클래스이다. 퍼사드 클래스가 제공됨으로써 일반 사용자는 서브 시스템의 상세 내용을 알 필요가 없어지며, 서브 시스템의 복잡한 구현으로부터 해방된다.
퍼사드 클래스는 다음과 같은 특징을 가진다.
- 퍼사드 클래스는 어디까지나 서브 시스템 내부에 작업을 위임할 뿐이며, 복잡한 구현을 가지지 않는다. 즉, 다양한 기능 덩어리인 서브 시스템으로부터 사용자의 용도에 맞는 창구(인터페이스)를 제공하는 역할만 한다.
- 퍼사드 클래스를 서브 시스템 자체가 이용하는 일은 없다. 퍼사드 클래스는 서브 시스템 말단의 창구이므로, 동일한 서브 시스템 내에서 사용되지 않는다.
- 퍼사드 패턴은 서브 시스템의 직접 사용을 방해하지 않는다. 퍼사드 클래스의 이용은 강제가 아니며, 필요하다면 서브 시스템의 기능을 직접 이용할 수 있다. 언어에 따라서는 네임스페이스나 패키지 스코프 등으로 서브 시스템을 사용자로부터 격리할 수도 있지만, 퍼사드 패턴 자체는 그러한 제한을 두지 않는다.
2. 1. 2. 클라이언트 (Client)
클라이언트는 퍼사드 패턴에서 퍼사드 클래스를 사용하여 서브시스템의 기능에 접근하는 객체이다.[1] 복잡한 서브시스템을 직접 다루는 대신, 클라이언트는 퍼사드가 제공하는 단순화된 인터페이스를 통해 필요한 기능을 요청한다.[2] 이는 서브시스템의 복잡성을 숨기고 사용 편의성을 높이며, 클라이언트와 서브시스템 간의 결합도를 낮추는 효과를 가져온다.UML 클래스 다이어그램에서 볼 수 있듯이, `Client` 클래스는 서브시스템 클래스(
Class1, Class2, Class3)에 직접 의존하지 않고, 오직 `Facade` 클래스와 상호작용한다. `Facade` 클래스가 서브시스템 클래스들을 대신하여 단순한 인터페이스를 제공하기 때문이다. 이를 통해 `Client`는 서브시스템의 내부 구조 변경에 영향을 덜 받게 되어 코드의 유지보수성과 재사용성이 향상된다.[4] 시퀀스 다이어그램은 이러한 상호작용을 시간 순서대로 보여준다. `Client` 객체가 `Facade` 객체에 특정 작업을 요청하면, `Facade` 객체는 이 요청을 받아 서브시스템 내의 적절한 객체들(Class1, Class2, Class3 인스턴스)에게 작업을 분배하고 실행시키는 과정을 나타낸다.클라이언트는 퍼사드를 이용함으로써 복잡한 서브시스템의 사용법을 익힐 필요 없이 필요한 기능만 쉽게 사용할 수 있다. 그러나 퍼사드 패턴이 서브시스템의 직접적인 사용을 막는 것은 아니다. 클라이언트는 필요에 따라 퍼사드를 통하지 않고 직접 서브시스템의 클래스나 기능에 접근할 수도 있다.
2. 1. 3. 패키지/서브시스템 (Package/Subsystem)
패키지 또는 서브시스템은 특정 기능을 수행하기 위해 함께 작동하는 클래스들의 집합으로, 소프트웨어 라이브러리나 API 묶음과 유사하다. 퍼사드 패턴에서 패키지/서브시스템은 실제 복잡한 로직과 기능을 담당하는 부분이다.퍼사드는 이러한 복잡한 패키지/서브시스템에 대한 단순화된 접근 창구를 제공하는 역할을 한다. 즉, 클라이언트(사용자 또는 다른 시스템 부분)는 패키지/서브시스템 내부의 복잡한 구조나 다양한 인터페이스를 직접 다룰 필요 없이, 퍼사드 클래스가 제공하는 간결한 인터페이스만을 통해 필요한 기능을 이용할 수 있다.[2]
예를 들어, 컴파일러를 하나의 서브시스템으로 볼 수 있다. 컴파일러는 내부적으로 어휘 분석기, 구문 분석기 등 여러 복잡한 구성 요소로 이루어져 있다. 이러한 구성 요소들은 그 자체로 다른 소프트웨어를 만드는 데 사용될 수 있는 서브시스템이다. 하지만 일반 사용자는 단순히 소스 코드를 컴파일하는 기능만 필요로 한다. 이때 퍼사드 클래스는 사용자가 필요로 하는 '컴파일' 기능만을 제공하는 역할을 하여, 사용자가 서브시스템의 복잡한 내부를 알 필요 없이 쉽게 컴파일러를 사용하도록 돕는다.
퍼사드 클래스는 기본적으로 서브시스템 내부의 기능들을 호출하여 작업을 위임할 뿐, 자체적으로 복잡한 로직을 가지지는 않는다. 또한, 퍼사드 패턴을 사용한다고 해서 서브시스템에 직접 접근하는 것이 막히는 것은 아니다. 필요하다면 클라이언트는 퍼사드를 통하지 않고 직접 서브시스템의 클래스나 기능들을 사용할 수도 있다.
3. 사용
퍼사드 패턴은 복잡한 하위 시스템(subsystem)을 더 쉽게 사용하도록 간단한 인터페이스를 제공하는 데 목적이 있다.[2] 또한, 클라이언트(호출하는 쪽)가 하위 시스템의 여러 객체에 직접 의존하는 것을 줄여, 시스템 간의 결합을 낮추는 효과도 가져온다.[2] 클라이언트는 복잡한 하위 시스템의 내부 구조를 알 필요 없이, 퍼사드 객체만을 통해 필요한 기능에 접근할 수 있게 된다.
퍼사드는 기본 객체에 대해 더 간단하고 쉬운 인터페이스를 제공하고자 할 때 주로 사용된다.[3] 이는 다른 구조 패턴들과 구별되는 점이다. 예를 들어, 어댑터 패턴은 기존 인터페이스를 클라이언트가 기대하는 다른 인터페이스로 변환하는 데 사용되며, 데코레이터 패턴은 객체의 원래 코드를 수정하지 않고 런타임에 동적으로 새로운 책임(기능)을 추가하는 데 사용된다.
| 패턴 | 의도 |
|---|---|
| 어댑터 | 클라이언트가 요구하는 인터페이스에 맞춰 기존 인터페이스를 변환한다. |
| 데코레이터 | 원래 객체를 감싸서 인터페이스에 동적으로 새로운 책임을 추가한다. |
| 퍼사드 | 복잡한 시스템에 대해 단순화된 인터페이스를 제공한다. |
퍼사드 패턴은 특히 다음과 같은 상황에서 유용하게 사용될 수 있다.
- 복잡한 시스템에 대한 간단한 인터페이스 제공: 여러 하위 시스템으로 구성된 복잡한 시스템을 사용할 때, 퍼사드를 통해 단순화된 단일 진입점을 제공하여 사용 편의성을 높인다.
- 시스템의 복잡성 은닉: 시스템 내부 구현이 매우 복잡하거나 이해하기 어려울 때, 퍼사드는 이러한 복잡성을 숨기고 필요한 기능만 노출한다.
- 계층화된 구조의 진입점: 계층화된 소프트웨어 구조에서 각 계층으로 접근하는 통일된 진입점을 제공하여 계층 간의 상호작용을 관리한다.
- 하위 시스템 간의 강한 결합 완화: 하위 시스템의 추상화와 구현이 서로 밀접하게 연결되어 있을 때, 퍼사드를 도입하여 클라이언트와 하위 시스템 간의 직접적인 의존성을 줄이고 결합도를 낮춘다.
예를 들어, 컴퓨터를 사용하는 상황을 생각해 볼 수 있다. 사용자는 컴퓨터 전원 버튼을 누르는 것만으로 복잡한 내부 부품들(CPU, 하드 드라이브, 메모리 등)의 작동 과정을 몰라도 컴퓨터를 켤 수 있다. 여기서 컴퓨터 본체(또는 운영체제)가 일종의 퍼사드 역할을 하여, 사용자와 복잡한 하드웨어 시스템 사이의 상호작용을 단순화하는 것이다.
또 다른 예시로 컴파일러를 들 수 있다.[1] 컴파일러는 내부적으로 어휘 분석기, 구문 분석기, 코드 생성기 등 여러 복잡한 구성 요소로 이루어져 있다. 하지만 일반적인 사용자는 소스 코드를 실행 가능한 프로그램으로 변환하는 컴파일 기능만 필요로 한다. 이때, 컴파일러의 주 인터페이스(예: 컴파일 명령어)가 퍼사드 역할을 하여, 사용자가 내부 구성 요소의 복잡한 작동 방식을 몰라도 쉽게 컴파일 기능을 사용할 수 있게 해준다. 사용자는 퍼사드 클래스가 제공하는 단순화된 인터페이스를 통해 하위 시스템의 세부 구현으로부터 자유로워진다.
4. 장점 및 고려사항
퍼사드 패턴의 주요 장점은 복잡한 서브시스템을 사용하기 쉽게 만든다는 점이다.[2] 서브시스템의 다양한 인터페이스를 감싸는 단순하고 일관된 단일 인터페이스(퍼사드 객체)를 제공함으로써, 클라이언트는 복잡한 내부 구조를 알 필요 없이 필요한 기능에 쉽게 접근할 수 있다.[2][3] 예를 들어 컴파일러의 경우, 사용자는 내부의 어휘 분석기나 구문 분석기 등 복잡한 구성 요소를 몰라도 퍼사드를 통해 '소스 코드 컴파일'이라는 단순화된 기능을 이용할 수 있다.[3]
이는 클라이언트와 서브시스템 간의 결합도를 낮추는 효과를 가져온다.[2] 클라이언트는 퍼사드 객체에만 의존하게 되므로, 서브시스템 내부의 변경 사항이 클라이언트에 미치는 영향을 최소화할 수 있다. 결과적으로 클라이언트 코드의 구현, 변경, 테스트 및 재사용이 더 용이해진다.[2]
또한, 계층화된 소프트웨어 구조에서 각 계층의 진입점 역할을 수행하여 시스템 구조를 명확하게 하는 데 도움을 줄 수 있다.[3]
하지만 퍼사드 패턴 사용 시 고려할 점도 있다. 퍼사드는 주로 사용될 기능들을 모아 단순화된 인터페이스를 제공하는 데 목적이 있으므로, 서브시스템의 모든 세부 기능에 접근해야 하는 클라이언트에게는 오히려 제약이 될 수 있다. 이런 경우 클라이언트는 퍼사드를 거치지 않고 직접 서브시스템의 구성 요소를 사용해야 할 수도 있다.
퍼사드 패턴은 서브시스템의 직접적인 사용을 제한하지 않는다.[3] 클라이언트는 필요에 따라 퍼사드의 단순화된 인터페이스를 이용하거나, 더 복잡한 기능이 필요하면 직접 서브시스템의 클래스나 함수를 호출할 수 있다.
퍼사드 클래스 자체는 일반적으로 복잡한 로직을 수행하기보다는, 클라이언트의 요청을 받아 서브시스템의 적절한 구성 요소에게 작업을 위임하는 역할을 주로 담당한다.[3]
5. 예제
다음은 클라이언트("당신")가 복잡한 시스템(CPU, 메모리, 하드 드라이브 등 컴퓨터 내부 부품)에 있는 퍼사드("컴퓨터")와 상호 작용하는 방법에 대한 추상적인 C++ 예시이다. `ComputerFacade` 클래스가 퍼사드 역할을 하며, 복잡한 부팅 과정을 `Start()` 메소드로 단순화하여 제공한다.
// 컴퓨터 내부 부품들을 나타내는 구조체들
struct CPU {
void Freeze(); // CPU 동작 일시 중지
void Jump(long position); // 특정 메모리 주소로 이동
void Execute(); // 명령어 실행
};
struct HardDrive {
char* Read(long lba, int size); // 하드 드라이브에서 데이터 읽기 (논리 블록 주소 기반)
};
struct Memory {
void Load(long position, char* data); // 메모리에 데이터 로드
};
// 퍼사드 클래스: 복잡한 시스템을 감싸는 단순한 인터페이스 제공
class ComputerFacade {
public:
// 복잡한 부팅 절차를 단순화한 메소드
void Start() {
cpu_.Freeze(); // 다른 장치 준비를 위해 CPU 정지
// 하드 드라이브의 부트 섹터에서 데이터를 읽어 메모리의 지정된 주소에 로드
memory_.Load(kBootAddress, hard_drive_.Read(kBootSector, kSectorSize));
cpu_.Jump(kBootAddress); // 부트 코드가 로드된 메모리 주소로 이동
cpu_.Execute(); // CPU 실행 시작 (부팅 시작)
}
private:
// 내부 시스템 구성 요소들 (클라이언트는 직접 접근하지 않음)
CPU cpu_;
Memory memory_;
HardDrive hard_drive_;
// 부팅 관련 상수 정의 (예시 값)
static const long kBootAddress = 0x00007C00; // 부트 코드가 로드될 메모리 주소
static const long kBootSector = 0; // 부트 섹터 번호
static const int kSectorSize = 512; // 섹터 크기 (바이트)
};
// 클라이언트 코드 (main 함수)
int main() {
ComputerFacade computer; // 퍼사드 객체 생성
// 클라이언트는 복잡한 내부 동작을 몰라도 Start() 호출만으로 컴퓨터를 시작
computer.Start();
return 0;
}
더 구체적인 자바 및 C# 예제는 아래 하위 섹션에서 확인할 수 있다.
5. 1. Java 예제
아래 자바 코드 예제는 사용자(you)가 퍼사드(컴퓨터)를 통해 컴퓨터 내부의 복잡한 부품들(CPU, 메모리, 하드 드라이브)에 직접 접근하는 대신, 간단한 인터페이스를 통해 상호작용하는 방식을 보여준다.'''컴퓨터 부팅 예제'''
이 예제에서 `Computer` 클래스는 퍼사드 역할을 한다. 사용자인 `You` 클래스는 컴퓨터 내부의 복잡한 부팅 과정(CPU 초기화, 메모리에 부트 데이터 로딩, CPU 실행 등)을 알 필요 없이, `Computer` 클래스의 `startComputer()` 메소드만 호출하면 된다.
/* 복잡한 내부 부품들 */
class CPU {
public void freeze() { /* ... */ } // CPU 동작 일시 중지
public void jump(long position) { /* ... */ } // 특정 메모리 주소로 이동
public void execute() { /* ... */ } // 명령어 실행
}
class Memory {
public void load(long position, byte[] data) { // 특정 주소에 데이터 로드
/* ... */
}
}
class HardDrive {
public byte[] read(long lba, int size) { // 논리 블록 주소(LBA)에서 데이터 읽기
/* ... */
return null; // 예시 코드: 실제 구현에서는 데이터를 읽어와야 함
}
}
/* 퍼사드 */
class Computer {
// 부팅 관련 상수 정의 (예시 값)
private static final long BOOT_ADDRESS = 0x00007C00; // 부트 코드가 로드될 메모리 주소
private static final long BOOT_SECTOR = 0; // 부트 섹터 번호
private static final int SECTOR_SIZE = 512; // 섹터 크기 (바이트)
public void startComputer() {
CPU cpu = new CPU();
Memory memory = new Memory();
HardDrive hardDrive = new HardDrive();
// 복잡한 부팅 절차를 단순화된 메소드 호출로 처리
cpu.freeze(); // 다른 장치들이 준비될 때까지 CPU 대기
// 하드 드라이브의 부트 섹터에서 데이터를 읽어 메모리의 부트 주소에 로드
memory.load(BOOT_ADDRESS, hardDrive.read(BOOT_SECTOR, SECTOR_SIZE));
cpu.jump(BOOT_ADDRESS); // 부트 코드가 있는 메모리 주소로 이동
cpu.execute(); // 부트 코드 실행 시작
}
}
/* 클라이언트 */
class You {
public static void main(String[] args) {
Computer facade = new Computer(); // 퍼사드 인스턴스 생성
// 클라이언트는 복잡한 내부 동작을 몰라도 startComputer() 호출만으로 컴퓨터를 시작
facade.startComputer();
}
}
'''자동차 운전 시뮬레이션 예제'''
다음은 자바를 이용한 또 다른 적용 예시이다. 운전 시뮬레이션 상황을 가정한다.
driving.Car: 자동차의 속도와 이동 거리를 관리하는 클래스.package driving;
class Car {
private int speed; // 현재 속도 (m/min)
private int distance; // 총 이동 거리 (m)
Car() {
this.speed = 0;
this.distance = 0;
}
// 속도 설정
void setSpeed(int speed) {
this.speed = speed;
}
// 주어진 시간(분)만큼 현재 속도로 주행하여 이동 거리 업데이트
void run(int minutes) {
this.distance += minutes * this.speed;
}
// 총 이동 거리 반환
int getDistance() {
return this.distance;
}
}
driving.Driver: 운전자가 자동차를 조작하는 행위를 나타내는 클래스.package driving;
class Driver {
private Car car; // 운전할 자동차 객체
Driver(Car car) {
this.car = car;
}
// 가속 페달을 밟아 속도 설정
void pushPedal(int speed) {
this.car.setSpeed(speed);
}
// 주어진 시간(분)만큼 운전
void drive(int minutes) {
this.car.run(minutes);
}
}
driving.DrivingSimulator: 퍼사드 역할을 수행하는 클래스. 자동차와 운전자 객체를 생성하고, 운전 과정을 시뮬레이션하는 복잡한 절차를 `simulate()` 메소드 하나로 단순화하여 제공한다.package driving;
public class DrivingSimulator {
// 운전 시뮬레이션 실행
public void simulate() {
Car c = new Car(); // 자동차 생성
Driver d = new Driver(c); // 운전자 생성 및 자동차 할당
// 운전 시나리오 실행 (복잡한 상호작용을 퍼사드가 처리)
d.pushPedal(700); // 속도를 700 m/min 으로 설정
d.drive(30); // 30분간 주행
d.pushPedal(750); // 속도를 750 m/min 으로 변경
d.drive(20); // 20분간 추가 주행
// 결과 출력
System.out.println("The travel distance is " + c.getDistance() + " m.");
}
}
FacadeTest: 클라이언트 코드. `DrivingSimulator` 퍼사드를 통해 시뮬레이션을 실행한다.import driving.DrivingSimulator;
public class FacadeTest {
public static void main(String[] argv) {
// 클라이언트는 DrivingSimulator의 simulate() 메소드만 호출하면 됨
new DrivingSimulator().simulate();
}
}
이 자동차 운전 예제에서 퍼사드에 해당하는 클래스는 `DrivingSimulator`이다. 클라이언트는 `Car` 클래스의 `setSpeed()`, `run()` 메소드나 `Driver` 클래스의 `pushPedal()`, `drive()` 메소드를 직접 호출할 필요 없이, `DrivingSimulator`의 `simulate()` 메소드 호출만으로 전체 운전 시뮬레이션 과정을 수행할 수 있다. 이처럼 퍼사드 패턴은 복잡한 서브시스템의 내부 구현을 숨기고, 사용하기 쉬운 단일 인터페이스를 제공하여 시스템 사용을 간편하게 만든다.
5. 2. C# 예제
wikitext// Facade pattern -- Structural example
using System;
namespace DoFactory.GangOfFour.Facade.Structural
{
// Mainapp test application
class MainApp
{
public static void Main()
{
Facade facade = new Facade();
facade.MethodA();
facade.MethodB();
// Wait for user
Console.Read();
}
}
// "Subsystem ClassA"
class SubSystemOne
{
public void MethodOne()
{
Console.WriteLine(" SubSystemOne Method");
}
}
// Subsystem ClassB"
class SubSystemTwo
{
public void MethodTwo()
{
Console.WriteLine(" SubSystemTwo Method");
}
}
// Subsystem ClassC"
class SubSystemThree
{
public void MethodThree()
{
Console.WriteLine(" SubSystemThree Method");
}
}
// Subsystem ClassD"
class SubSystemFour
{
public void MethodFour()
{
Console.WriteLine(" SubSystemFour Method");
}
}
// "Facade"
class Facade
{
SubSystemOne one;
SubSystemTwo two;
SubSystemThree three;
SubSystemFour four;
public Facade()
{
one = new SubSystemOne();
two = new SubSystemTwo();
three = new SubSystemThree();
four = new SubSystemFour();
}
public void MethodA()
{
Console.WriteLine("\nMethodA() ---- ");
one.MethodOne();
two.MethodTwo();
four.MethodFour();
}
public void MethodB()
{
Console.WriteLine("\nMethodB() ---- ");
two.MethodTwo();
three.MethodThree();
}
}
}
6. 관련 패턴
퍼사드 패턴은 다른 디자인 패턴과 구별되는 목적을 가지며, 특히 어댑터 패턴, 데코레이터 패턴 등과 비교될 수 있다. 퍼사드는 복잡한 하위 시스템에 대해 더 쉽고 단순화된 인터페이스를 제공하고자 할 때 사용된다.[3] 반면, 어댑터는 특정 인터페이스를 클라이언트가 기대하는 다른 인터페이스 형태로 변환하여 호환되지 않는 인터페이스 간의 호환성을 맞추는 데 중점을 둔다. 데코레이터는 객체를 감싸 런타임에 추가적인 책임(기능)을 동적으로 부여하는 데 사용된다.[3]
각 패턴의 주요 의도는 다음과 같이 요약할 수 있다.
| 패턴 | 의도 |
|---|---|
| 어댑터 | 클라이언트가 예상하는 것에 맞춰 한 인터페이스를 다른 인터페이스로 변환 |
| 데코레이터 | 원래 코드를 래핑하여 인터페이스에 동적으로 책임을 추가 |
| 퍼사드 | 단순화된 인터페이스 제공 |
또한, 추상 팩토리 패턴은 퍼사드 패턴의 구체적인 예시로 간주될 수 있다.
6. 1. 어댑터 패턴 (Adapter Pattern)
어댑터 패턴은 특정 인터페이스를 클라이언트가 기대하는 다른 인터페이스 형태로 변환하여, 인터페이스 호환성 문제를 해결하기 위해 사용된다.[3] 즉, 호환되지 않는 인터페이스 때문에 함께 작동할 수 없는 클래스들이 함께 작동하도록 돕는다. 이는 래퍼(Wrapper)가 특정 인터페이스를 준수하고 다형적인 동작을 지원해야 할 때 유용하다.[3]퍼사드 패턴이 복잡한 하위 시스템에 대한 단순화된 인터페이스를 제공하는 것을 목표로 하는 반면, 어댑터 패턴은 기존 인터페이스를 클라이언트 요구사항에 맞게 변환하는 데 중점을 둔다. 또한, 데코레이터 패턴은 런타임에 객체에 새로운 책임(기능)을 동적으로 추가하는 방식이라는 점에서 차이가 있다.[3]
6. 2. 데코레이터 패턴 (Decorator Pattern)
데코레이터는 원래 코드를 감싸서 인터페이스에 동적으로 책임을 추가하는 디자인 패턴이다. 이를 통해 런타임에 인터페이스의 동작을 추가하거나 변경할 수 있다.[3]6. 3. 추상 팩토리 패턴 (Abstract Factory Pattern)
추상 팩토리 패턴은 퍼사드 패턴의 구체적인 예라고 볼 수 있다. 이때, 추상 팩토리 패턴의 'ConcreteFactory' 클래스가 퍼사드 패턴의 'Facade' 클래스에 해당한다.참조
[1]
서적
Design Patterns: Elements of Reusable Object-Oriented Software
https://archive.org/[...]
Addison Wesley
[2]
웹사이트
The Facade design pattern - Problem, Solution, and Applicability
http://w3sdesign.com[...]
2017-08-12
[3]
서적
Head First Design Patterns
https://www.goodread[...]
O'Reilly
2012-07-02
[4]
웹사이트
The Facade design pattern - Structure and Collaboration
http://w3sdesign.com[...]
2017-08-12
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com
